﻿using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;

namespace Angle.Krill.Utils
{
    public class ScreenRecorderHelper
    {
        private readonly static object obj = new object();
        private volatile static ScreenRecorderHelper instance;

        private Timer timer = new Timer();
        private VideoWriter videoWriter;
        private Rectangle screenRect;
        private bool isStop = false;

        private ScreenRecorderHelper() { }
        /// <summary>
        /// 缓存
        /// </summary>
        public static ScreenRecorderHelper Instance
        {
            get
            {
                if (null == instance)
                {
                    lock (obj)
                    {
                        instance = new ScreenRecorderHelper();
                    }
                }

                return instance;
            }
        }

        /// <summary>
        /// 获取 桌面屏幕图片
        /// </summary>
        /// <returns></returns>
        public Bitmap GetScreenImgByteArray(Rectangle bounds)
        {
            Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format24bppRgb);

            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.CopyFromScreen(System.Drawing.Point.Empty, System.Drawing.Point.Empty, bounds.Size, CopyPixelOperation.SourceCopy);
                GC.Collect();
                return bitmap;
            }
        }
        public void StartScreenRecord(string filePath, double fps, Rectangle bounds)
        {
            this.screenRect = bounds;

            System.Drawing.Size size = new System.Drawing.Size(bounds.Width, bounds.Height);
            if (this.videoWriter == null)
            {
                this.videoWriter = new OpenCvSharp.VideoWriter(
                    filePath, OpenCvSharp.FourCC.XVID,
                    fps,
                    new OpenCvSharp.Size(size.Width, size.Height));
            }
            timer.Interval = (int)Math.Ceiling(this.videoWriter.Fps);
            timer.Tick += Timer_Tick;
            this.isStop = false;

            timer.Enabled = true;
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            if (!this.isStop)
            {
                this.videoWriter.Write(BitmapToMat(this.GetScreenImgByteArray(this.screenRect)));
            }
            else
            {
                timer.Enabled = false;
            }
        }

        public void StopScreenRecord()
        {
            this.isStop = true;
        }

        public void EndScreenRecord()
        {
            this.isStop = true;

            if (this.videoWriter != null)
            {
                this.videoWriter.Release();
                this.videoWriter.Dispose();
                this.videoWriter = null;
                GC.Collect();
            }
        }

        public OpenCvSharp.Mat BitmapToMat(Bitmap bmp)
        {
            MemoryStream ms = null;
            OpenCvSharp.Mat source = null;
            try
            {
                return BitmapConverter.ToMat(bmp);
            }
            catch (Exception e)
            {
                Trace.WriteLine(e.ToString());
            }
            finally
            {
                if (ms != null)
                {
                    ms.Close();
                    ms = null;
                }
                GC.Collect();
            }
            return source;

        }
    }
}